package main

import (
	"container/list"
	"sync"
)

type ExampleQueue struct {
	queue map[int]*list.List
	conds map[int]*sync.Cond
}

func NewQueue() *ExampleQueue {
	q := &ExampleQueue{}
	q.queue = map[int]*list.List{}
	q.conds = map[int]*sync.Cond{}
	return q
}

func (e *ExampleQueue) Push(clientId int, msg Message) {
	if _, ok := e.queue[clientId]; !ok {
		e.queue[clientId] = list.New()
		lock := &sync.Mutex{}
		lock.Lock()
		e.conds[clientId] = sync.NewCond(lock)
	}
	e.queue[clientId].PushBack(msg)
	e.conds[clientId].Signal()
}

func (e *ExampleQueue) Pop(clientId int) Message {
	if _, ok := e.queue[clientId]; !ok {
		e.queue[clientId] = list.New()
		lock := &sync.Mutex{}
		lock.Lock()
		e.conds[clientId] = sync.NewCond(lock)
	}
	var elem *list.Element
	if e.queue[clientId].Len() == 0 {
		e.conds[clientId].Wait()
	}
	elem = e.queue[clientId].Front()
	return e.queue[clientId].Remove(elem).(Message)
}
